package com.open4cn.simulator.protocol.huagao;

import cn.hutool.core.util.HexUtil;
import com.open4cn.simulator.core.ext.HuaGaoInMessage;
import com.open4cn.simulator.core.util.StrFillUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @author yinxiaopeng
 * @version 1.0.0
 * @company 致景科技
 * @department 飞梭BU/研发
 * @description 华高协议解析
 * @Email yinxiaopeng@zj.tech
 * @date 2022-05-02 01:55
 */
public class HuaGaoDecoder extends ByteToMessageDecoder {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    // 正文开始(STX)
    private static final String STX = "02";

    // 半包-缓存
    private ByteBuf cache = Unpooled.buffer();

    // 触发缓存的次数
    private int cacheTime = 1;

    // 允许触发缓存的最大次数
    private int maxCacheTime = 3;

    private int currentProtocolDataLength = 0;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        cache.writeBytes(in);

        // 报文前4个字节是定义的协议长度
        while (cache.readableBytes() > 4) {
            if (currentProtocolDataLength == 0) {
                currentProtocolDataLength = getProtocolDataLength(cache);
            }
            // 剩余报文必须大于协议长度,才是完整数据
            if (cache.readableBytes() >= currentProtocolDataLength) {
                HuaGaoInMessage huaGaoInMessage = getMessage(cache, currentProtocolDataLength);
                out.add(huaGaoInMessage);
                // 重置
                currentProtocolDataLength = 0;
                cache.clear();
            } else {
                if (cacheTime >= maxCacheTime) {
                    cacheTime = 0;
                    currentProtocolDataLength = 0;
                    cache.clear();
                } else {
                    cacheTime++;
                    break;
                }
            }
        }
    }

    /**
     * 构造消息
     *
     * @param cache
     * @param protocolDataLength
     * @return
     */
    private HuaGaoInMessage getMessage(ByteBuf cache, int protocolDataLength) {
        byte[] data = new byte[protocolDataLength];
        cache.readBytes(data);

        HuaGaoInMessage inMessage = new HuaGaoInMessage(data);
        inMessage.setProtocolDataLe(protocolDataLength);
        inMessage.setCommand(getCommand(data));
        return inMessage;
    }


    /**
     * 解析协议长度
     * 读取前4个字节,就是协议长度
     *
     * @param byteBuf
     * @return
     */
    private int getProtocolDataLength(ByteBuf byteBuf) {
        if (byteBuf.readableBytes() < 4) {
            return 0;
        }
        byte[] header = new byte[4];
        byteBuf.readBytes(header);

        StringBuilder headerStr = new StringBuilder();
        for (int i = header.length - 1; i >= 0; i--) {
            int each = header[i] & 0xFF;
            String eachStr = Integer.toHexString(each);
            eachStr = StrFillUtil.fillLeft(eachStr, 2, "0");
            headerStr.append(eachStr);
        }
        return Integer.parseInt(headerStr.toString(), 16);
    }

    /**
     * 解析命令字
     *
     * @param msg
     * @return
     */
    private String getCommand(byte[] msg) {
        String hexStr = HexUtil.encodeHexStr(msg);
        logger.info("华高设备接收到数据(hex){}", hexStr);

        // 查找开始位标记
        int indexOf = hexStr.indexOf(STX);
        if (indexOf == -1) {
            logger.warn("{}未包含开始标记位[02]", hexStr);
            return null;
        }

        // 截取命令字
        hexStr = hexStr.substring(indexOf);
        if (hexStr.length() < 10) {
            logger.warn("{}未包含命令字", hexStr);
            return null;
        }

        return HexUtil.decodeHexStr(hexStr.substring(6, 10));
    }
}
